home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 May: Tool Chest / Developer CD Series May 1996 (Tool Chest) (Apple Computer) (1996).iso / Sample Code / Snippets / Networking / AppleTalk Libraries / AFP.c next >
Encoding:
C/C++ Source or Header  |  1991-12-03  |  24.1 KB  |  769 lines  |  [TEXT/MPS ]

  1. /*------------------------------------------------------------------------------
  2. #
  3. #    AFP.c : this module contains the functions used to  :
  4. #        - log on an AppleShare server (username/password or guest)
  5. #        - get the number of volumes and their list
  6. #        - get the list of directories with their access rights.
  7. #        - get the server time
  8. #
  9. #    Once you have logged on, a session is open, it's up to you to logout.
  10. #    Once you have open a volume, you have to close it.
  11. #
  12. #
  13. #    Versions:    1.0                    10/91
  14. #    Built with MPW 3.2
  15. #
  16. #    C.Buttin - Apple Computer Europe            
  17. #
  18. ------------------------------------------------------------------------------*/
  19.  
  20. #include <Limits.h>
  21. #include <Types.h>
  22. #include <ToolUtils.h>
  23. #include <Memory.h>
  24. #include <OSUtils.h>
  25. #include <stdIO.h>
  26. #include <String.h>
  27. #include <Strings.h>
  28. #include <Devices.h>
  29. #include <OSUtils.h>
  30. #include <errors.h>
  31. #include <AppleTalk.h>
  32.  
  33. /* defined used for AppleTalk */
  34. #define sync        false            /* synchronous operation */
  35. #define quantumSize 578                /* ATP packet size */
  36. #define countOffset 4    
  37.  
  38. /* structures used by GetDirectories */
  39. typedef struct OffSpringParam {
  40.     Byte    length;
  41.     Byte    flags;
  42.     short    offsetName;
  43.     long    dirID;
  44.     Byte    UAM[4];
  45. }OffSpringParam;
  46.  
  47. typedef OffSpringParam *OffSpringPtr;
  48.  
  49. typedef struct InfoDir {
  50.     short     UAM;                /* access right for this directory */
  51.     long     dirID;                
  52.     Str32    dirName;
  53. }InfoDir;
  54.  
  55. typedef InfoDir *InfoDirPtr;
  56.  
  57.  
  58. /* C routines declaration. */
  59. /*    InitXPP : Open the ATP and XPP drivers
  60.     Output : noErr or the error number if an error occurred */
  61. pascal OSErr InitXPP(void);
  62.  
  63. /* AFP Calls */
  64. /* GetServerInfo :    Get in the reply buffer, information about the server :
  65.             - name
  66.             - machine type
  67.             - UAMs
  68.     lnput : AppleTalk server address
  69.             Pointer on a reply buffer
  70.             length of this buffer
  71.     Output : noErr or the error number if an error occurred */
  72. pascal OSErr GetServerInfo(AddrBlock *serverAddress,Ptr replyBuffer,short buffLength);
  73.  
  74. /* LogOnwithName :
  75.     lnput : AppleTalk address of the server
  76.             UserName
  77.             Password
  78.             Pointer on a SCCBlock, must be of size scbMemSize, must remain valid
  79.             and locked during the whole session (i.e. till LogOut)
  80.     Output : session number or the error number if an error occurred */
  81. pascal short LogOnwithName(AddrBlock *serverAddress,Ptr theName,Ptr thePassword,Ptr SCBBlock);
  82.  
  83. /* LogOnAsGuest :
  84.     lnput : AppleTalk address of the server
  85.             Pointer on a SCCBlock, must be of size scbMemSize, must remain valid
  86.             and locked during the whole session (i.e. till LogOut)
  87.     Output : session number or the error number if an error occurred */
  88. pascal short LogOnAsGuest(AddrBlock *serverAddress,Ptr SCBBlock);
  89.  
  90. /* GetServerParams :    Get in the reply buffer,the number of volumes 
  91.                         and the volume list
  92.     lnput : Session Reference Number
  93.             Pointer on a reply buffer
  94.             length of this buffer
  95.     Output : noErr or the error number if an error occurred */
  96. pascal OSErr GetServerParams(short sessNum,Ptr replyBuffer,short buffLength);
  97.  
  98. /* OpenVolume :    Open an AppleShare volume
  99.     lnput : Session Reference Number
  100.             volume name
  101.     Output : volume number
  102.              error number if an error occurred */
  103. pascal short OpenVolume(short sessNum,Ptr volumeName,short* volID);
  104.  
  105. /* GetVolumePrivileges :    Returns the privileges of the volume.
  106.     lnput : Session Reference Number
  107.             volume ID
  108.     Output : volume privileges or error number if an error occurred */
  109. pascal short GetVolumePrivileges(short sessionNum,short volumeID);
  110.  
  111. /* GetDirectories :    Returns in a buffer the list of directories :
  112.                     name    (pascal string)
  113.                     dirID
  114.                     access mode
  115.     lnput : Session Reference Number
  116.             volume ID
  117.             directory to be listed
  118.             buffer to receive the data
  119.             length of this buffer
  120.             max number of dirs to be got
  121.     Output : error number if an error occurred */
  122. pascal OSErr GetDirectories(short sessNum,short volID,long dirID,
  123.                             Ptr buffer,short buffLength,short reqCount);
  124.  
  125. /* CloseVolume :    Close an AppleShare volume
  126.     lnput : Volume Reference Number */
  127. pascal void CloseVolume(short sessNum,short volumeID);
  128.  
  129. /* LogOut :    stop the session
  130.     lnput : Session Reference Number
  131.             Pointer SCBBlock
  132.     Output : noErr or the error number if an error occurred */
  133. pascal OSErr LogOut(short sessNum,Ptr SCBBlock);
  134.  
  135. /* Server utilities */
  136. /* CheckUAM : verify if a User Access Method is available 
  137.     Input : string containing the method name
  138.             reply buffer got from GetServerInfo
  139.     Output : Boolean, true is the method is available */
  140. pascal Boolean CheckUAM(const Str32 theMethod,Ptr replyBuffer);
  141.  
  142. /* GetServerTime : extract the server time from the reply 
  143.                    got from GetServerParams
  144.     Input : reply buffer
  145.     Output : server time (in seconds, on Macintosh Unit (since Januray 1904) */
  146. pascal unsigned long GetServerTime(Ptr replyBuffer);
  147.  
  148. /* Volumes utilities */
  149. /* GetNumberVolumes : extract the number of volumes of the server
  150.                       from the reply got from GetServerParams
  151.     Input : reply buffer
  152.     Output : number of volumes */
  153. pascal short GetNumberVolumes(Ptr replyBuffer);
  154.  
  155. /* ExtractVolumeName : extract the nth volume from the reply buffer
  156.                       got from GetServerParams
  157.     Input : reply buffer
  158.             volumeNumber
  159.             empty string to receive the volume name (as a Pascal string)
  160.     Output : Boolean, false if volume number is too big */
  161. pascal Boolean ExtractVolumeName(Ptr replyBuffer,short volumeNumber,Str255 theVol);
  162.  
  163.  
  164. /* Directories utilities */
  165. /* GetNumberDirs : extract the number of directories from the reply got 
  166.                    from GetDirectories
  167.     Input : reply buffer
  168.     Output : number of Dirs */
  169. pascal short GetNumberDirs(Ptr replyBuffer);
  170.  
  171. /* ExtractDirInfo : extract the info regarding the nth dir from the reply buffer
  172.                       got from GetDirectories
  173.     Input : reply buffer
  174.             dirNumber
  175.             Pointer on a dirInfo structure
  176.     Output : Boolean, false if dirNumber is too big */
  177. pascal Boolean ExtractDirInfo(Ptr replyBuffer,short dirNumber,InfoDirPtr theDir);
  178.  
  179.  
  180.                             /**** CODE  ****/
  181.  
  182. pascal OSErr InitXPP(void)
  183. {
  184.     short     drivernum;
  185.     OSErr     error;
  186.     
  187.     /* open .ATP driver and .XPP driver */
  188.     if ((error = ATPLoad()) != noErr)
  189.         return error;
  190.     /* open .XPP driver */
  191.     return OpenXPP(&drivernum);
  192. } /* InitXPP */
  193.  
  194.  
  195.                           /* AFP functions */
  196.  
  197. pascal OSErr GetServerInfo(AddrBlock *serverAddress,Ptr replyBuffer,short buffLength)
  198. {
  199.     XPPParamBlock *XPPBlock;                /* to build parameter blocks for AFP */
  200.     OSErr        error;
  201.  
  202.     if ((error = InitXPP()) != noErr)
  203.         return error;
  204.     
  205.     if (!(XPPBlock = (XPPParamBlock *)NewPtrClear(sizeof(XPPParamBlock))))
  206.         return MemError();
  207.  
  208.     XPPBlock->XPP.ioRefNum = xppRefNum;        /* driver reference number */
  209.     /* prepare command information : 
  210.         no input provided except command - see IA 13-95.
  211.         In the Mac inplementation you must use ASPGetStatus (see IM vol.V-541) */
  212.      XPPBlock->OPEN.serverAddr = *serverAddress;   /* AppleTalk address of the server */
  213.     XPPBlock->XPP.aspTimeout = 2;                    /* Timeout for ATP */
  214.      XPPBlock->XPP.aspRetry = 2; 
  215.     XPPBlock->XPP.rbPtr = replyBuffer;                 /* Reply buffer pointer */
  216.     XPPBlock->XPP.rbSize = buffLength;
  217.  
  218.     error = ASPGetStatus((XPPParmBlkPtr)XPPBlock,sync);
  219.     DisposPtr((Ptr)XPPBlock);
  220.     return error;
  221.  
  222. } /* GetServerInfo */
  223.  
  224. /* Log on server */
  225. pascal short LogOnwithName(AddrBlock *serverAddress,Ptr theName,Ptr thePassword,Ptr SCBBlock)
  226. {
  227.     AFPLoginPrm *XPPBlock;                            /* to build parameter blocks for AFP */
  228.     short         i,lgInfo,cbsize;
  229.     char        XPPReply[quantumSize*8];            /* used to get AFP replies (max. size 8 ATP packet) */
  230.     char        XPPCmd[quantumSize];                /* used to send AFP commands */
  231.     OSErr        error;
  232.     short        result;
  233.     char        userAuthInfo[50];
  234.     
  235.     /* information used by Login function */
  236.     char        AFPVersion[30];
  237.     char        AuthentMethod[30];
  238.     
  239.     strcpy(AFPVersion, "\pAFPVersion 2.0");
  240.     strcpy(AuthentMethod, "\pCleartxt passwrd");
  241.     /* prepare user info */
  242.     lgInfo = (short)theName[0]+1;
  243.     BlockMove(theName,userAuthInfo,lgInfo);
  244.     if (lgInfo % 2 == 0)    {
  245.         /* pad with a null byte to have password on even boundary */
  246.         lgInfo++;
  247.         userAuthInfo[lgInfo] = '\0';
  248.         }
  249.     for (i = 1; i <= thePassword[0]; i++,lgInfo++) 
  250.             userAuthInfo[lgInfo] = thePassword[i];
  251.     for (; i <= 8; i++,lgInfo++)                 /* pad with null bytes if necessary */
  252.             userAuthInfo[lgInfo] = '\0';
  253.         
  254.     if (!(XPPBlock = (AFPLoginPrm *)NewPtrClear(sizeof(AFPLoginPrm))))
  255.         return MemError();
  256.     
  257.     XPPBlock->ioRefNum = xppRefNum;
  258.     XPPBlock->ioCompletion = nil;
  259.      XPPBlock->aspTimeout = 1;                    /* Timeout for ATP */
  260.      XPPBlock->aspRetry = 2;                      /* Retry count for ATP */
  261.      XPPBlock->afpAddrBlock = *serverAddress;    /* AppleTalk address of the server */
  262.      XPPBlock->afpAttnRoutine = nil ;            
  263.     XPPBlock->rbPtr = (Ptr)XPPReply;               /* Reply buffer pointer */
  264.     XPPBlock->rbSize = quantumSize;                 /* Reply buffer size */
  265.     
  266.     /* prepare command information :
  267.        1st byte : command (login)
  268.        2nd Pascal string : AFP version
  269.        3rd Pascal string : Authentication Method - see Inside AppleTalk 13-105
  270.        4th user information : username - password */
  271.     XPPCmd[0] = afpLogin;
  272.     cbsize = 1;
  273.     BlockMove(AFPVersion,XPPCmd+cbsize,AFPVersion[0]+1);
  274.     cbsize += AFPVersion[0]+1;
  275.     BlockMove(AuthentMethod,XPPCmd+cbsize,AuthentMethod[0]+1);
  276.     cbsize += AuthentMethod[0]+1;
  277.  
  278.     /* add user info */
  279.     BlockMove(userAuthInfo,XPPCmd+cbsize,lgInfo);
  280.     cbsize += lgInfo;
  281.     
  282.     XPPBlock->cbPtr = (Ptr)XPPCmd;                 /* Command block pointer */
  283.     XPPBlock->cbSize = cbsize;
  284.     XPPBlock->afpSCBPtr = (Ptr) SCBBlock;         /* SCB pointer in AFP login */
  285.  
  286.     if ((error = AFPCommand((XPPParmBlkPtr)XPPBlock,sync)) != noErr)
  287.         result = error;
  288.     else
  289.         if (XPPBlock->cmdResult != noErr)
  290.            result =  XPPBlock->cmdResult ;
  291.           else result =  XPPBlock->sessRefnum;            /* return session number */
  292.     
  293.     DisposPtr((Ptr)XPPBlock);
  294.     return result;
  295. } /* LogOnwithName */
  296.  
  297. pascal short LogOnAsGuest(AddrBlock *serverAddress,Ptr SCBBlock)
  298.   {
  299.     AFPLoginPrm *XPPBlock;                            /* to build parameter blocks for AFP */
  300.     short         cbsize;
  301.     char        XPPReply[quantumSize*8];            /* used to get AFP replies (max. size 8 ATP packet) */
  302.     char        XPPCmd[quantumSize];                /* used to send AFP commands */
  303.     OSErr        error;
  304.     short        result;
  305.     /* information used by Login function */
  306.     char        AFPVersion[30];
  307.     char        AuthentMethod[30];
  308.     
  309.     strcpy(AFPVersion, "AFPVersion 2.0");
  310.     strcpy(AuthentMethod, "No User Authent");
  311.     
  312.     if (!(XPPBlock = (AFPLoginPrm *)NewPtrClear(sizeof(AFPLoginPrm))))
  313.         return MemError();
  314.     
  315.     XPPBlock->ioRefNum = xppRefNum;
  316.     XPPBlock->ioCompletion = nil;
  317.      XPPBlock->aspTimeout = 1;                    /* Timeout for ATP */
  318.      XPPBlock->aspRetry = 2;                      /* Retry count for ATP */
  319.      XPPBlock->afpAddrBlock = *serverAddress;    /* AppleTalk address of the server */
  320.      XPPBlock->afpAttnRoutine = nil ;            
  321.     XPPBlock->rbPtr = (Ptr)XPPReply;               /* Reply buffer pointer */
  322.     XPPBlock->rbSize = quantumSize;                 /* Reply buffer size */
  323.     
  324.     /* prepare command information :
  325.        1st byte : command (login)
  326.        2nd Pascal string : AFP version
  327.        3rd Pascal string : Authentication Method - see Inside AppleTalk 13-104 */
  328.     XPPCmd[0] = afpLogin;
  329.     XPPCmd[1] = strlen(AFPVersion);
  330.     strcpy(XPPCmd+2,AFPVersion);
  331.     cbsize = strlen(XPPCmd);
  332.     XPPCmd[cbsize] = strlen(AuthentMethod);
  333.     strcpy(XPPCmd+cbsize+1,AuthentMethod);
  334.     cbsize = strlen(XPPCmd);
  335.     
  336.     XPPBlock->cbPtr = (Ptr)XPPCmd;                 /* Command block pointer */
  337.     XPPBlock->cbSize = cbsize;
  338.     XPPBlock->afpSCBPtr = (Ptr) SCBBlock;         /* SCB pointer in AFP login */
  339.  
  340.     if ((error = AFPCommand((XPPParmBlkPtr)XPPBlock,sync)) != noErr)
  341.         result = error;
  342.     else
  343.         if (XPPBlock->cmdResult != noErr)
  344.            result =  XPPBlock->cmdResult ;
  345.           else result =  XPPBlock->sessRefnum;            /* return session number */
  346.     
  347.     DisposPtr((Ptr)XPPBlock);
  348.     return result;
  349. }    /* LogOnAsGuest */
  350.         
  351. /* get the server parameters (AFP call : GetSrvParms) */
  352. pascal OSErr GetServerParams(short sessNum,Ptr replyBuffer,short buffLength)
  353. {
  354.     XPPPrmBlk     *XPPBlock;                /* to build parameter blocks for AFP */
  355.     char        XPPCmd[quantumSize];    /* used to send AFP commands */
  356.     OSErr        error;
  357.     
  358.     if (!(XPPBlock = (XPPPrmBlk *)NewPtrClear(sizeof(XPPPrmBlk))))
  359.         return MemError();
  360.  
  361.     XPPBlock->ioRefNum = xppRefNum;        /* driver reference number */
  362.     /* prepare command information : 
  363.         no input provided except command - see IA 13-98 */
  364.      XPPCmd[0]  = afpGetSParms;
  365.     
  366.     XPPBlock->sessRefnum = sessNum;
  367.     XPPBlock->aspTimeout = 2;            /* Timeout for ATP */
  368.      XPPBlock->aspRetry = 2; 
  369.     XPPBlock->cbPtr = (Ptr)XPPCmd;
  370.     XPPBlock->cbSize = 1;               /* Command block size */
  371.     XPPBlock->rbPtr = replyBuffer;      /* Reply buffer pointer */
  372.     XPPBlock->rbSize = buffLength;
  373.       XPPBlock->wdSize = 0;               /* Write Data size */
  374.     XPPBlock->wdPtr = nil;              /* Write Data pointer */
  375.     
  376.     error = AFPCommand((XPPParmBlkPtr)XPPBlock,sync);
  377.     DisposPtr((Ptr)XPPBlock);
  378.     return error;
  379.  }
  380.  
  381. /* Open an AppleShare volume */
  382. pascal OSErr OpenVolume(short sessNum,Ptr volumeName,short* volID)
  383. {
  384.  
  385.     XPPPrmBlk     *XPPBlock;                /* to build parameter blocks for AFP */
  386.     char        XPPCmd[quantumSize];    /* used to send AFP commands */
  387.     OSErr        error;
  388.     char        replyBuffer[100];
  389.     
  390.     if (!(XPPBlock = (XPPPrmBlk *)NewPtrClear(sizeof(XPPPrmBlk))))
  391.         return MemError();
  392.  
  393.     XPPBlock->ioRefNum = xppRefNum;        /* driver reference number */
  394.     /* prepare command information :
  395.         command
  396.         bitmap
  397.         volume name as a pascal string - see IA 13-121 */
  398.      XPPCmd[0]  = afpOpenVol;
  399.     XPPCmd[1]  = 0;
  400.     XPPCmd[2] = 0;
  401.     XPPCmd[3] = 0x20;    /* we just want the volume ID (bit 5 in bitmap) */
  402.     BlockMove(volumeName,XPPCmd+4,volumeName[0]+1);
  403.  
  404.     XPPBlock->sessRefnum = sessNum;
  405.     XPPBlock->aspTimeout = 2;                /* Timeout for ATP */
  406.      XPPBlock->aspRetry = 2; 
  407.     XPPBlock->cbPtr = (Ptr)XPPCmd;
  408.     XPPBlock->cbSize = volumeName[0]+5;        /* Command block size */
  409.     XPPBlock->rbPtr = replyBuffer;             /* Reply buffer pointer */
  410.     XPPBlock->rbSize = 100;
  411.       XPPBlock->wdSize = 0;                   /* Write Data size */
  412.     XPPBlock->wdPtr = nil;                     /* Write Data pointer */
  413.     
  414.     if ((error = AFPCommand((XPPParmBlkPtr)XPPBlock,sync)) == noErr)
  415.         if (XPPBlock->cmdResult != noErr)
  416.               error =  XPPBlock->cmdResult ;
  417.         else {
  418.         /* volume parameters are contained within the reply buffer
  419.            the volume ID is at byte 2 and it's two bytes long 
  420.            (see Inside AppleTalk pp 13-102 && 13-121 */
  421.             BlockMove(replyBuffer+ 2,volID,2);    /* return volume number */
  422.             }
  423.     if (error)
  424.         *volID = -1;
  425.  
  426.     DisposPtr((Ptr)XPPBlock);
  427.     return error;
  428.  }    /* OpenVolume */
  429.  
  430. /* getting the volume privileges is the same as getting the root privileges */
  431. pascal short GetVolumePrivileges(short sessionNum,short volumeID)
  432. {
  433.  
  434.  
  435.     XPPPrmBlk         *XPPBlock;                /* to build parameter blocks for AFP */
  436.     char            XPPCmd[quantumSize];    /* used to send AFP commands */
  437.     OSErr            error;
  438.     short            lg;
  439.     Byte            buffer[100];
  440.     long            dirID = 2;                /* the root has the dirID 2 */
  441.     Byte            UAM[4];
  442.     
  443.     if (!(XPPBlock = (XPPPrmBlk *)NewPtrClear(sizeof(XPPPrmBlk))))
  444.         return MemError();
  445.     
  446.     XPPBlock->ioRefNum = xppRefNum;        /* driver reference number */
  447.     /* prepare command information :
  448.         command    : FPGetFileDirParms            see IA - 13-83 
  449.         0
  450.         volumeID
  451.         DirectoryID            of the directory we are looking for
  452.         File BitMap            not used
  453.         Directory BitMap
  454.         PathType
  455.         PathName            not used (must be set to empty string)     */
  456.  
  457.      lg = 0;
  458.     XPPCmd[lg++]  = afpGetFlDrParms;
  459.     XPPCmd[lg++]  = 0;
  460.     BlockMove(&volumeID,XPPCmd+lg,2);        /* volumeID */
  461.     lg += 2;
  462.     BlockMove(&dirID,XPPCmd+lg,4);            /* dirID */
  463.     lg += 4;
  464.     XPPCmd[lg++] = 0;                        /* File BitMap */
  465.     XPPCmd[lg++] = 0;                        /* File BitMap */
  466.     XPPCmd[lg++] = 0x10;                    /* Directory BitMap : Access Rights */
  467.     XPPCmd[lg++] = 0;                        /* Directory BitMap */
  468.     XPPCmd[lg++] = 2;                        /* pathname is long name */
  469.     XPPCmd[lg++] = '\0';                    /* pathname is empty */    
  470.     
  471.     XPPBlock->sessRefnum = sessionNum;
  472.     XPPBlock->aspTimeout = 2;                /* Timeout for ATP */
  473.      XPPBlock->aspRetry = 2; 
  474.     XPPBlock->cbPtr = (Ptr)XPPCmd;
  475.     XPPBlock->cbSize = lg;                    /* Command block size */
  476.     XPPBlock->rbPtr = buffer;                 /* Reply buffer pointer */
  477.     XPPBlock->rbSize = 100;
  478.       XPPBlock->wdSize = 0;                   /* Write Data size */
  479.     XPPBlock->wdPtr = nil;                     /* Write Data pointer */
  480.     
  481.     if ((error = AFPCommand((XPPParmBlkPtr)XPPBlock,sync)) == noErr)
  482.         if (XPPBlock->cmdResult != noErr)
  483.               error =  XPPBlock->cmdResult ;
  484.     /* the access rights are set up after the file and dir bitmaps
  485.         + 2 bytes of flags */
  486.     BlockMove(buffer + 6,UAM,4);
  487.     /* return the first octet as a short */
  488.     lg = (short)UAM[0];
  489.     DisposPtr((Ptr)XPPBlock);
  490.     return ((error == noErr) ? lg : error);
  491.  
  492. } /* GetVolumePrivileges */
  493.  
  494. /* Get the list of subdirectories of a directory with their name, 
  495.    dirID and  privileges */
  496. pascal OSErr GetDirectories(short sessNum,short volID,long dirID,
  497.                             Ptr buffer,short buffLength,short reqCount)
  498. {
  499.  
  500.     XPPPrmBlk         *XPPBlock;                /* to build parameter blocks for AFP */
  501.     char            XPPCmd[quantumSize];    /* used to send AFP commands */
  502.     OSErr            error;
  503.     short            temp,lg;
  504.     
  505.     if (!(XPPBlock = (XPPPrmBlk *)NewPtrClear(sizeof(XPPPrmBlk))))
  506.         return MemError();
  507.     /* we expect to receive as reply, for each dir in the directory :
  508.         - the offset to dirname    (short)
  509.         - the dirID    (long)
  510.         - the Access rights of the dir (long)
  511.         - the name of the dir (Str32) */
  512.     if ((reqCount * 50) > buffLength)
  513.         return afpParmErr;                    /* buffer too small */    
  514.  
  515.     XPPBlock->ioRefNum = xppRefNum;        /* driver reference number */
  516.     /* prepare command information :
  517.         command    : FPEnumerate            see  IA 13-73
  518.         0
  519.         volumeID
  520.         DirectoryID                to be browsed
  521.         File BitMap                not used
  522.         Directory BitMap        dirName + dirID + access rights
  523.         ReqCount
  524.         StartIndex
  525.         MaxReplySize
  526.         PathType
  527.         PathName                not used (must be set to empty string) */
  528.      lg = 0;
  529.     XPPCmd[lg++]  = afpEnumerate;
  530.     XPPCmd[lg++]  = 0;
  531.     BlockMove(&volID,XPPCmd+lg,2);            /* volumeID */
  532.     lg += 2;
  533.     BlockMove(&dirID,XPPCmd+lg,4);            /* parID */
  534.     lg += 4;
  535.     XPPCmd[lg++] = 0;                        /* File BitMap */
  536.     XPPCmd[lg++] = 0;                        /* File BitMap */
  537.     XPPCmd[lg++] = 0x11;                    /* Directory BitMap : Access Rights + dirID */
  538.     XPPCmd[lg++] = 0x40;                    /* Directory BitMap : names */
  539.     BlockMove(&reqCount,XPPCmd+lg,2);        /* requested count */
  540.     lg += 2;
  541.     temp = 1;                                /* start index */
  542.     BlockMove(&temp,XPPCmd+lg,2);
  543.     lg += 2;
  544.     temp = reqCount * 50;                    /* maximum size of reply block */
  545.     BlockMove(&temp,XPPCmd+lg,2);
  546.     lg += 2;
  547.     XPPCmd[lg++] = 2;                        /* pathname is long name */
  548.     XPPCmd[lg++] = '\0';                    /* pathname is empty */    
  549.     
  550.     XPPBlock->sessRefnum = sessNum;
  551.     XPPBlock->aspTimeout = 2;                /* Timeout for ATP */
  552.      XPPBlock->aspRetry = 2; 
  553.     XPPBlock->cbPtr = (Ptr)XPPCmd;
  554.     XPPBlock->cbSize = lg;                    /* Command block size */
  555.     XPPBlock->rbPtr = buffer;                 /* Reply buffer pointer */
  556.     XPPBlock->rbSize = buffLength;
  557.       XPPBlock->wdSize = 0;                   /* Write Data size */
  558.     XPPBlock->wdPtr = nil;                     /* Write Data pointer */
  559.     
  560.     if ((error = AFPCommand((XPPParmBlkPtr)XPPBlock,sync)) == noErr)
  561.         if (XPPBlock->cmdResult != noErr)
  562.               error =  XPPBlock->cmdResult ;
  563.     DisposPtr((Ptr)XPPBlock);
  564.     return error;
  565. }    /* GetDirectories */
  566.  
  567. /* close an AppleShare volume */
  568. pascal void CloseVolume(short sessNum,short volumeID)
  569. {
  570.  
  571.  
  572.     XPPPrmBlk     *XPPBlock;                /* to build parameter blocks for AFP */
  573.     char        XPPCmd[quantumSize];    /* used to send AFP commands */
  574.     OSErr        error;
  575.     
  576.     if (!(XPPBlock = (XPPPrmBlk *)NewPtrClear(sizeof(XPPPrmBlk))))
  577.         return ;
  578.  
  579.     XPPBlock->ioRefNum = xppRefNum;        /* driver reference number */
  580.     /* prepare command information :
  581.         command  1 byte
  582.         0         1 byte
  583.         volumeID 2 bytes         see IA 13-63 */
  584.      XPPCmd[0]  = afpVolClose;
  585.     XPPCmd[1] = 0;
  586.     BlockMove(&volumeID,XPPCmd+2,2);
  587.  
  588.     XPPBlock->sessRefnum = sessNum;
  589.     XPPBlock->aspTimeout = 2;                /* Timeout for ATP */
  590.      XPPBlock->aspRetry = 2; 
  591.     XPPBlock->cbPtr = (Ptr)XPPCmd;
  592.     XPPBlock->cbSize = 4;                    /* Command block size */
  593.     XPPBlock->rbPtr = nil;                     /* Reply buffer pointer */
  594.     XPPBlock->rbSize = 0;
  595.       XPPBlock->wdSize = 0;                   /* Write Data size */
  596.     XPPBlock->wdPtr = nil;                     /* Write Data pointer */
  597.     
  598.     error = AFPCommand((XPPParmBlkPtr)XPPBlock,sync);
  599.     DisposPtr((Ptr)XPPBlock);
  600.  } 
  601.  /* CloseVolume */
  602.  
  603. /* Close the session */
  604. pascal OSErr LogOut(short sessNum,Ptr SCBBlock)
  605. {
  606. #pragma unused (SCBBlock)
  607.  
  608.     XPPPrmBlk     *XPPBlock;                /* to build parameter blocks for AFP */
  609.     char        XPPCmd[quantumSize];    /* used to send AFP commands */
  610.     OSErr        error;
  611.     
  612.     if (!(XPPBlock = (XPPPrmBlk *)NewPtrClear(sizeof(XPPPrmBlk))))
  613.         return MemError();
  614.     XPPBlock->ioRefNum = xppRefNum;        /* driver reference number */
  615.      /* prepare command information :
  616.         just the command     see IA 13-108 */
  617.      XPPCmd[0]  = afpLogout;
  618.     XPPBlock->cbPtr = (Ptr)XPPCmd;          /*Command block pointer */
  619.     XPPBlock->cbSize = 1;
  620.    
  621.     XPPBlock->sessRefnum = sessNum;
  622.     XPPBlock->aspTimeout = 2;            /*Timeout for ATP */
  623.     XPPBlock->aspRetry = 2; 
  624.  
  625.     error = AFPCommand((XPPParmBlkPtr)XPPBlock,sync);
  626.     DisposPtr((Ptr)XPPBlock);
  627.     return error;
  628.     
  629. }    /* LogOut */
  630.  
  631.  
  632.                     /***         UTILITIES            ***/
  633.  
  634.  
  635. /* Check if a UAM is available */
  636. pascal Boolean CheckUAM(const Str32 theMethod,Ptr replyBuffer)
  637. {
  638.     short     offset,i,j,numUAMs,length;
  639.     Ptr        p;
  640.     
  641.     BlockMove(replyBuffer+4, &offset,2);    /* to get the offset of UAMs in the buffer */
  642.     numUAMs = (short)(*(replyBuffer + offset));
  643.     /* UAMs are packed as Pascal string. By comparing the strings,
  644.            we can see if find the right UAM */
  645.     p =    replyBuffer + offset + 1;
  646.     for (i = 1, length = (short)*p; i <= numUAMs ;i++)    {
  647.         for (j = 1; j <= length;j++)
  648.             if (theMethod[j] != p[j])
  649.                 break;
  650.         if (j > length)                    /* we found it */
  651.             return true;
  652.         else 
  653.             if (i < numUAMs)     {
  654.                 p += length+1;
  655.                 length = (short)*p;
  656.                 }
  657.         }
  658.     return false;
  659. }    /* CheckUAM */
  660.  
  661. /* calculate the server time in seconds in Macintosh units */                    
  662. pascal unsigned long GetServerTime(Ptr replyBuffer)
  663. {
  664.     long         theTime,theLocalTime;
  665.     DateTimeRec theDate;
  666.     
  667.     /* the Volumes buffer contains :        see IA p 13-99
  668.             - server time (long) : this value is the number of seconds
  669.               measured from  12:00 am on Januray 1,2000 */
  670.     
  671.     BlockMove(replyBuffer,&theTime,4);
  672.     /* calculate the number of seconds till Januray 1, 2000 */
  673.     theDate.day = 1;
  674.     theDate.month = 1;
  675.     theDate.year = 2000;
  676.     theDate.hour = 0;
  677.     theDate.minute = 0;
  678.     theDate.second = 0;
  679.     Date2Secs(&theDate,(unsigned long* )&theLocalTime);
  680.     /* add the two values to get the right time */
  681.     theTime += theLocalTime;
  682.     return theTime;
  683.     
  684. } /* GetServerTime */
  685.  
  686. /* Get the number of volumes of an AppleShare server */
  687. pascal short GetNumberVolumes(Ptr replyBuffer)
  688. {
  689.     short numVol;
  690.  
  691.     /* the Volumes buffer contains :        see IA p 13-99
  692.             - server time    (long)
  693.             - num of vols.    (short) */
  694.             
  695.     numVol = (short)*(replyBuffer+4);
  696.     return numVol;
  697.     
  698. } /* GetNumberVolumes */
  699.  
  700. /* extract from the AFP reply buffer a volume name as a pascal string */
  701. pascal Boolean ExtractVolumeName(Ptr replyBuffer,short volumeNumber,char *theVol)
  702. {
  703.     /* the structure of the buffer is defined as follow (see Inside AppleTalk
  704.        p 13-98) :
  705.            1 byte for flags (volume has password )
  706.         Volume name as a Pascal string. Volume names are delimited by a null char
  707.         if even number of chars.*/
  708.         
  709.     short i,j,length;
  710.     
  711.     if (volumeNumber > GetNumberVolumes(replyBuffer))
  712.         return false;
  713.     replyBuffer = replyBuffer+5;                    /* position at 1st volume name */
  714.     for (i = 1; i <= volumeNumber;i++) {
  715.         length = (short)(*(++replyBuffer));            /* skeep flag byte */
  716.         for (j = 0; j <= length;j++,replyBuffer++)    /* volume Name */
  717.             if (i == volumeNumber)
  718.                 theVol[j] = *replyBuffer;
  719.         }
  720.     return true;
  721. } /* ExtractVolumeName */
  722.  
  723.  
  724. /* Directories utilities */
  725. /* Get the number of subdirectories of a directory */
  726. pascal short GetNumberDirs(Ptr replyBuffer)
  727. {
  728.     short count;
  729.     
  730.     /* the GetDirectories buffer contains :        see IA p 13-76
  731.             - file BitMap    (short)
  732.             - dirBitMap        (short)
  733.             - count            (short) */
  734.             
  735.     BlockMove(replyBuffer+4,&count,2);
  736.     return count;                
  737. } /* GetNumberDirs */
  738.  
  739. /* Get the name, dirID and access rights of a directory */
  740. pascal Boolean ExtractDirInfo(Ptr p,short dirNumber,InfoDirPtr theDir)
  741. {
  742.     short    i,length;
  743.     
  744.     /* verify if dirNumber is OK */
  745.     if (dirNumber > GetNumberDirs(p))
  746.         return false;
  747.     /* skip countInfo in the buffer */ 
  748.     p += 6;
  749.  
  750.     for (i = 1; i < dirNumber;i++)        /* skip first dirs */ 
  751.         p = p+((OffSpringPtr)p)->length;    
  752.         
  753.     /* we expect to receive in reply, for each directory :
  754.         - the offset to dirname
  755.         - the dirID    (long)
  756.         - the Access rights of the dir (long)
  757.         - the name of the dir (Str32)         see IA 13-74 */
  758.  
  759.     theDir->UAM = (short)(((OffSpringPtr)p)->UAM[0]);
  760.     theDir->dirID = ((OffSpringPtr)p)->dirID;
  761.  
  762.  
  763.     /* skip first bytes (lenght,flags) */
  764.     length = ((OffSpringPtr)p)->offsetName + 2;    
  765.     p += length;
  766.     BlockMove(p,theDir->dirName,*p+1);
  767.     return true;
  768. } /* ExtractDirInfo */
  769.